/*
 * Package il.ac.biu.cs.grossmm.api.data
 * File Status.java
 * 
 * This is a part of presence service framework API. 
 * See javadoc for more information.
 *  
 * Copyright (C) 2006 Grossmann Mark
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
 * MA  02110-1301, USA.
 */

package il.ac.biu.cs.grossmm.api.flow;

/**
 * Represents a subscription state. This class is abstract and therefore can be
 * instantiated directly. Subclasses of this class define specific subscription
 * states such as active, pending or no-resource. A subscription state A may be
 * a particular case (sub-state) of another subscription state B. In this case
 * class representing B should extend class A. Method <tt>isKindOf()</tt>
 * provides a conventinal way to determine if a one state the same as or a
 * sub-state of another subscription state.
 * 
 */
public abstract class Status {
	final String reason;

	/**
	 * Initial status which is basicly is undefined status
	 */
	public final static Status INIT = null;

	/**
	 * Subscription is active and notifiations can be received
	 */
	public final static Active ACTIVE = new Active();

	/**
	 * The resource exists, but notifications can be sent at the moment. A
	 * reason for it might be absence of authorization rules for the watcher
	 * interested in receiving notifications. A subscription may exist in a
	 * PENDING state for a long state, and usually switch to either ACTIVE or
	 * DEACTIVATED state eventually (there are other possibilities though.
	 */
	public final static Pending PENDING = new Pending();

	/**
	 * Subscription is in process of switching to active state but initial state
	 * of the resource is still unknown. This state is different from the
	 * <tt>PENDING</tt> state since the process of switching between states is
	 * very fast (milliseconds) and it is known that the subscription stat will
	 * becomme active
	 */
	public final static Activating ACTIVATING = new Activating();

	/**
	 * The subscription key does not match any output data point
	 */
	public final static Unmatched UNMATCHED = new Unmatched();

	/**
	 * The subscription key matches an output data point but the corresponding
	 * resource does not exist (e.g. PRESENTITY is not registered)
	 */
	public final static Noresource NORESOURCE = new Noresource();
	
	/**
	 * The watcher is not authorized to subscribe to this resource
	 */
	public final static Forbidden FORBIDDEN = new Forbidden();

	/**
	 * The subscription is not active due to an internal error. The state of
	 * subscription may change when error is resolved (for example connection to
	 * database is resumed)
	 */
	public final static Error ERROR = new Error();

	public abstract static class Success extends Status {
		protected Success()
		{
		}

		protected Success(String reason)
		{
			super(reason);
		}
	}

	public abstract static class Failure extends Status {
		protected Failure()
		{
		}

		protected Failure(String reason)
		{
			super(reason);
		}
	}

	/**
	 * Represents an active subscription state. This state implies that
	 * subscribed resource exists, the data can be inspected and event
	 * notifications are fired when resource data changes.
	 */
	public static final class Active extends Success {
		protected Active()
		{
		}

		public Active(String reason)
		{
			super(reason);
		}
	}

	/**
	 * Represents a "pending" subscription state.
	 */
	public static class Pending extends Success {

		protected Pending()
		{
		}

		public Pending(String reason)
		{
			super(reason);
		}
	}

	/**
	 * Represents an "activating" resource state. This state implies that
	 * subscribed resource exists and potentially can be accessed, but the data
	 * is not available yet.
	 */
	public static final class Activating extends Status {
		private Activating()
		{
		}
	}

	public static class Unmatched extends Failure {
	}

	/**
	 * Represents a "no-resource" resource state. This state implies that
	 * subscribed resource does not exist. The subscription state may change
	 * when resource is created.
	 */
	public static class Noresource extends Failure {
		protected Noresource()
		{
		}

		public Noresource(String reason)
		{
			super(reason);
		}
	}
	
	/**
	 * Represents a "forbidden" resource state. This state corresponds to the
	 * situation when a watcher trying to subscribe to a resource
	 * is not authorized to subscribe to this resource
	 */
	public static class Forbidden extends Failure {
		protected Forbidden()
		{
		}

		public Forbidden(String reason)
		{
			super(reason);
		}
	}

	/**
	 * Represents a state of subscription deactivated due to an internal error
	 * or data access error
	 */
	public static class Error extends Status {

		protected Error()
		{
		}

		public Error(String reason)
		{
			super(reason);
		}
	}

	/**
	 * Creates a new SubscriptionState without detailed reason.
	 * 
	 */
	protected Status()
	{
		reason = "";
	}

	/**
	 * Creates a new SubscriptionState with detailed reason.
	 * 
	 */
	protected Status(String reason)
	{
		this.reason = reason;
	}

	public final String getReason()
	{
		return reason;
	}

	/**
	 * Provides a conventinal way to determine if this state is state the same
	 * as or a sub-state of a specified subscription state.
	 * 
	 * @param status
	 *            the subscription state to check against
	 * @return true iff if this state is state the same as or a sub-state of the
	 *         specified subscription state
	 */
	public final boolean isKindOf(Status status)
	{
		return getClass().isAssignableFrom(status.getClass());
	}

	@Override
	public String toString()
	{
		return getClass().getSimpleName() + " (" + reason + ")";
	}
}
